Skip to main content
Version: 6.0.0

triggerSmartContract

Triggers a state-changing (non pure / non view) contract method and returns a TransactionWrapper containing the unsigned transaction. The transaction still needs to be signed via tronWeb.trx.sign and broadcast via tronWeb.trx.sendRawTransaction. See more about Trigger Smart Contract.

Recommended: pass arguments via options.funcABIV2 + options.parametersV2

Use options.funcABIV2 + options.parametersV2 uniformly in all new code, and migrate existing code to this approach over time. This path encodes arguments through ABI v2 (encodeParamsV2ByABI); it not only handles tuple, nested tuple[], and other ABI v2 types correctly, but is also fully compatible with the simple flat types that ABI v1 supports — so it can serve as the single unified entry point for passing arguments.

The legacy positional parameters argument is retained only for backward compatibility with simple flat signatures and is not recommended for new code.

When options.funcABIV2 is present, the positional parameters argument is ignored — pass [] (or omit it).

Usage

const transactionWrapper = await tronWeb.transactionBuilder.triggerSmartContract(
contractAddress,
functionSelector,
options,
parameters,
issuerAddress
);

Parameters

ArgumentDescriptionTypeRequired
contractAddressThe smart contract address (base58 or hex).StringYes
functionSelectorFunction signature to invoke, e.g. transfer(address,uint256). Whitespace is automatically stripped. Can be omitted only when options.input is provided to supply raw call data.StringYes *
optionsTrigger options. Pass funcABIV2 + parametersV2 here to encode arguments (recommended). See TriggerSmartContractOptions. Defaults: feeLimit = tronWeb.feeLimit, callValue = 0.TriggerSmartContractOptionsNo
parametersLegacy positional arguments. Use only for flat signatures (no tuple). Ignored when options.funcABIV2, options.shieldedParameter, or options.rawParameter is supplied.Array<{ type: string; value: unknown }>No
issuerAddressSender (caller) address. Falls back to tronWeb.defaultAddress.hex.StringNo

* functionSelector can be left empty if options.input provides raw hex call data.

Argument-encoding paths (priority, highest first)

The trigger builder picks exactly one source for the function arguments, in this order:

  1. options.rawParameter — already-encoded hex calldata (with or without 0x prefix).
  2. options.shieldedParameter — alias of rawParameter for shielded-pool flows.
  3. options.funcABIV2 + options.parametersV2recommended default. Encoded via encodeParamsV2ByABI; supports tuple, nested tuple[], dynamic arrays, etc.
  4. Positional parameters — legacy ABI v1 encoder. Works for flat signatures only; does not support tuples.
  5. options.input — used as raw data when functionSelector is omitted entirely.

Notes on parameter encoding

  • address and address[] values are normalized to the EVM 0x… form before encoding; you may pass base58 (T…), hex (41…), or 0x… strings.
  • trcToken is internally treated as uint256 when ABI-encoded.
  • When options.txLocal is true, the transaction is constructed entirely on the client (the function selector + parameters are hashed locally with keccak256) and no network request is made; otherwise the node's wallet/triggersmartcontract endpoint is called.
  • options.permissionId may be supplied for multi-signature transactions.

Validation

The following constraints are enforced before the request is issued; violations throw synchronously:

  • feeLimit must be a positive integer.
  • callValue must be a non-negative integer.
  • parameters must be an array.
  • contractAddress must be a valid TRON address.
  • issuerAddress, tokenId, and tokenValue are validated when provided.

Returns

A wrapper which contains the unsigned transaction object.

interface TransactionWrapper {
result: {
result: boolean;
};
/**
* The unsigned transaction object created by calling the contract function.
*/
transaction: Transaction;
}

Example

const funcABIV2 = {
name: 'transfer',
type: 'function',
inputs: [
{ name: '_to', type: 'address' },
{ name: '_value', type: 'uint256' }
],
outputs: [{ type: 'bool' }],
stateMutability: 'nonpayable'
};

const options = {
feeLimit: 100_000_000,
callValue: 0,
tokenValue: 10,
tokenId: '1000001',
txLocal: true,
funcABIV2,
parametersV2: ['TV3nb5HYFe2xBEmyb3ETe93UGkjAhWyzrs', 100]
};

const transactionWrapper = await tronWeb.transactionBuilder.triggerSmartContract(
"TQQg4EL8o1BSeKJY4MJ8TB8XK7xufxFBvK",
"transfer(address,uint256)",
options,
[], // positional parameters ignored when funcABIV2 is set
"TM2TmqauSEiRf16CyFgzHV2BVxBejY9iyR"
);
{
"result": {
"result": true
},
"transaction": {
"visible": false,
"txID": "482b1a3b61894f75ea25bd10b14335a4db86c7e2c642ae07abc5a8ae45fb0027",
"raw_data": {
"contract": [
{
"parameter": {
"value": {
"data": "a9059cbb000000000000000000000000d148171f1ceeeb40d668c47d70e7e94e679775590000000000000000000000000000000000000000000000000000000000000064",
"token_id": 1000001,
"owner_address": "417946f66d0fc67924da0ac9936183ab3b07c81126",
"call_token_value": 10,
"contract_address": "419e62be7f4f103c36507cb2a753418791b1cdc182"
},
"type_url": "type.googleapis.com/protocol.TriggerSmartContract"
},
"type": "TriggerSmartContract"
}
],
"ref_block_bytes": "3a27",
"ref_block_hash": "83ca272ba6030b83",
"expiration": 1581935001000,
"fee_limit": 100000000,
"timestamp": 1581934943649
},
"raw_data_hex": "0a023a27220883ca272ba6030b8340a8fbb195852e5ab401081f12af010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e7472616374127a0a15417946f66d0fc67924da0ac9936183ab3b07c811261215419e62be7f4f103c36507cb2a753418791b1cdc1822244a9059cbb000000000000000000000000d148171f1ceeeb40d668c47d70e7e94e679775590000000000000000000000000000000000000000000000000000000000000064280a30c1843d70a1bbae95852e900180c2d72f"
}
}

Example with a tuple input (struct):

// solidity: function setStruct((address a, trcToken b, address c) _s)
const funcABIV2 = {
name: 'setStruct',
type: 'function',
inputs: [
{
name: '_s',
type: 'tuple',
components: [
{ name: 'a', type: 'address' },
{ name: 'b', type: 'trcToken' },
{ name: 'c', type: 'address' }
]
}
],
outputs: []
};

const transactionWrapper = await tronWeb.transactionBuilder.triggerSmartContract(
'TQQg4EL8o1BSeKJY4MJ8TB8XK7xufxFBvK',
'setStruct((address,trcToken,address))',
{
feeLimit: 100_000_000,
funcABIV2,
parametersV2: [['TPL66VK2gCXNCD7EJg9pgJRfqcRazjhUZY', 1000100, 'TPL66VK2gCXNCD7EJg9pgJRfqcRazjhUZY']]
}
);

Legacy: positional parameters (flat signatures only)

const parameter = [
{ type: 'address', value: 'TV3nb5HYFe2xBEmyb3ETe93UGkjAhWyzrs' },
{ type: 'uint256', value: 100 }
];
const transactionWrapper = await tronWeb.transactionBuilder.triggerSmartContract(
'TQQg4EL8o1BSeKJY4MJ8TB8XK7xufxFBvK',
'transfer(address,uint256)',
{ feeLimit: 100_000_000, callValue: 0 },
parameter
);

Pre-encoded calldata: options.rawParameter

Use this when you already have ABI-encoded argument bytes (e.g. cached from a previous call or produced by an external signer). Supply only the arguments portion — the 4-byte function selector is still derived from functionSelector by the builder. The 0x prefix is optional.

You can produce the encoded bytes with the same encoder TronWeb uses internally — tronWeb.utils.abi.encodeParamsV2ByABI — so the result is guaranteed to match what funcABIV2 would have produced:

const funcABIV2 = {
name: 'transfer',
type: 'function',
inputs: [
{ name: '_to', type: 'address' },
{ name: '_value', type: 'uint256' }
],
outputs: [{ type: 'bool' }],
stateMutability: 'nonpayable'
};

const rawParameter = tronWeb.utils.abi.encodeParamsV2ByABI(funcABIV2, ['TV3nb5HYFe2xBEmyb3ETe93UGkjAhWyzrs', 100]);
// rawParameter is now (0x prefix is optional):
// 0x000000000000000000000000d148171f1ceeeb40d668c47d70e7e94e67977559
// 0000000000000000000000000000000000000000000000000000000000000064

const transactionWrapper = await tronWeb.transactionBuilder.triggerSmartContract(
'TQQg4EL8o1BSeKJY4MJ8TB8XK7xufxFBvK',
'transfer(address,uint256)',
{
feeLimit: 100_000_000,
callValue: 0,
rawParameter // overrides funcABIV2 / parametersV2 / positional parameters
},
[],
'TM2TmqauSEiRf16CyFgzHV2BVxBejY9iyR'
);

To bypass the functionSelector step entirely and provide the full calldata (selector + arguments) as a single hex string, omit functionSelector and use options.input instead.

Sign and broadcast

After obtaining the wrapper:

const signedTx = await tronWeb.trx.sign(transactionWrapper.transaction);
const result = await tronWeb.trx.sendRawTransaction(signedTx);